﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace DZRemoteController
{
	class ComPortInputer :IInputable
	{
		private char refreshByte;
		private char startCodeByte;
		private char stopCodeByte;
		private byte startAudioByte;
		private byte stopAudioByte;
		private int interval;
		private DateTime lastTime;

		public event EventHandler<CodeRecievedEventArgs> CodeRecieved;
		public event EventHandler RefreshRecieved;

		private SerialPort port;
		private string currentCode;
		public ComPortInputer()
		{
			ComPortConfigSection comSection = (ComPortConfigSection)ConfigurationManager.GetSection("comPortSection");
			SerialPortPropertiesElement prop = comSection.Options;
			port = new SerialPort(prop.PortName, prop.BaudRate, prop.Parity, prop.DataBits, prop.StopBits);
			currentCode = String.Empty;
			startCodeByte = (char)comSection.Protocol.StartPackageByte;
			stopCodeByte = (char)comSection.Protocol.StopPackageByte;
			startAudioByte = comSection.Protocol.StartByte;
			stopAudioByte = comSection.Protocol.StopByte;
			interval = comSection.Protocol.ClearInterval;
			refreshByte = (char)comSection.Protocol.RefreshByte;
		}

		public void Start()
		{
			port.Open();
			port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
			lastTime = DateTime.Now;
		}

		void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
		{
			if ( DateTime.Now - lastTime > new TimeSpan(0, 0, 0, 0, interval))
				currentCode = String.Empty;
			currentCode += port.ReadExisting();
			bool needRefresh = currentCode.Contains(refreshByte.ToString());
			currentCode = currentCode.Replace(refreshByte.ToString(), String.Empty);

			string[] codes = ProcessCurrentCodeLine();
			foreach (string code in codes)
			{
				OnCodeRecieved(this, new CodeRecievedEventArgs(code));
				Thread.Sleep(500);
			}
			if (codes.Length == 0 && needRefresh)
				OnRefreshRecieved(this, EventArgs.Empty);


			lastTime = DateTime.Now;
		}


		private string[] ProcessCurrentCodeLine()
		{
			List<string> codes = new List<string>();
			int currentStartPos = 0;
			int currentStopPos = 0;
			//Удаляем все данные до получения символа начала посылки, начиная с символа конца посылки 
			while ((currentStartPos = currentCode.IndexOf(startCodeByte)) != -1)
			{
				currentStopPos = currentCode.LastIndexOf(stopCodeByte, currentStartPos, currentStartPos);
				currentCode = currentCode.Remove(currentStopPos + 1, currentStartPos - currentStopPos);
			}

			if (currentCode.Contains(stopCodeByte.ToString()))
			{
				codes.AddRange(currentCode.Split(new char[] { startCodeByte, stopCodeByte }, StringSplitOptions.RemoveEmptyEntries));
				currentCode = currentCode.Substring(currentCode.LastIndexOf(stopCodeByte)+1);
				if(currentCode != string.Empty && codes.Count != 0)
					codes.RemoveAt(codes.Count-1);
			}
			return codes.ToArray();
		}

		private void OnCodeRecieved(object sender, CodeRecievedEventArgs args)
		{
			if (CodeRecieved != null)
				CodeRecieved(sender, args);
		}

		private void OnRefreshRecieved(object sender, EventArgs empty)
		{
			if (RefreshRecieved != null)
				RefreshRecieved(sender, empty);
		}

		public void StartResponse()
		{
			port.Write(new byte[]{startAudioByte},0,1);
		}

		public void EndResponse()
		{
			GameState st = GameController.State;
			port.Write(new byte[] { stopAudioByte, st.LastEventNo, st.MissionNo, st.CodesLeft }, 0, 4);
		}

	}
}
